#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "st7789.h"
#include "xfont.h"
static const char* TAG = "XFont";
#define FontxDebug 0 // for Debug

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
const char *s64 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@#*$";
void InitXFont(XFont* xfont, const char* fontPath) {
    ESP_LOGE(TAG, "InitXFont  --");
	if (xfont->isInit == true)
        return;
        ESP_LOGE(TAG, "InitXFont  -- 1\n");
	 xfont->file = fopen(fontPath, "r");
    if (!xfont->file) {
        printf("Failed to open font file.\n");
        ESP_LOGE(TAG, "Failed to open font file.\n");
        return;
    }
    ESP_LOGE(TAG, "InitXFont  -- 1\n");
    uint8_t buf_total_str[6];
    uint8_t buf_font_size[2];
    uint8_t buf_bin_type[2];

    fread(buf_total_str, 1, 6, xfont->file);
    fread(buf_font_size, 1, 2, xfont->file);
    fread(buf_bin_type, 1, 2, xfont->file);

    char s1[7] = {0};
    char s2[3] = {0};
    char s3[3] = {0};

    memcpy(s1, buf_total_str, 6);
    memcpy(s2, buf_font_size, 2);
    memcpy(s3, buf_bin_type, 2);
    ESP_LOGE(TAG, "InitXFont  -- 1\n");
    xfont->total_font_cnt = strtoll(s1, NULL, 16);//获取字体总数
    ESP_LOGE(TAG, "InitXFont  total_font_cnt %d\n", xfont->total_font_cnt);
    xfont->font_size = atoi(s2);//获取字体大小
    ESP_LOGE(TAG, "InitXFont  font_size %d\n", xfont->font_size);
    xfont->bin_type = atoi(s3);//获取字体由多少进制数显示
    ESP_LOGE(TAG, "InitXFont  bin_type %d\n", xfont->bin_type);
    xfont->font_page = getFontPage(xfont->font_size, xfont->bin_type);//获取字体页面大小
    ESP_LOGE(TAG, "InitXFont  font_page %d\n", xfont->font_page);
    //ESP_LOGE(TAG, "InitXFont  -- 1\n");
    xfont->font_unicode_cnt = xfont->total_font_cnt * 5;
    ESP_LOGE(TAG, "InitXFont  font_unicode_cnt %d\n", xfont->font_unicode_cnt);
    xfont->unicode_begin_idx = 6 + 2 + 2 + xfont->total_font_cnt * 5;
    ESP_LOGE(TAG, "InitXFont  unicode_begin_idx %d\n", xfont->unicode_begin_idx);
    ESP_LOGE(TAG, "InitXFont  -- 1\n");
    xfont->strAllUnicodes = (char*)malloc(xfont->font_unicode_cnt + 1);
    fread(xfont->strAllUnicodes, 1, xfont->font_unicode_cnt, xfont->file);
    xfont->strAllUnicodes[xfont->font_unicode_cnt] = '\0';
    //ESP_LOGE(TAG, "InitXFont  strAllUnicodes  -- %s\n", xfont->strAllUnicodes);
    xfont->isInit = true;
    ESP_LOGE(TAG, "InitXFont  -- 2\n");
}

// 获取字体页面大小
int getFontPage(int font_size, int bin_type) {
    int total = font_size * font_size;
    int hexCount = 8;
    if (bin_type == 32) hexCount = 10;
    if (bin_type == 64) hexCount = 12;
    int hexAmount = total / hexCount;
    if (total % hexCount > 0) hexAmount += 1;
    return hexAmount * 2;
}

// // 从字符数组获取字符串
// char* getStringFromChars(uint8_t* bs, int l) {
//     char* ret = (char*)malloc(l + 1);
//     memcpy(ret, bs, l);
//     ret[l] = '\0';
//     return ret;
// }


// 将UTF-8编码转换为Unicode编码
char* getUnicodeFromUTF8(XFont* xfont,const char* s) {
    int len = strlen(s);
    char* result = (char*)malloc(len * 4 + 1);
    if (!result) {
        ESP_LOGE(TAG, "Failed to allocate memory for Unicode");
        return NULL;
    }
    memset(result, 0, len * 4 + 1);

    for (int i = 0; i < len; i++) {
        if (s[i] >= 1 && s[i] <= 127) { // ASCII 字符
            char hex[3] = {0};
            snprintf(hex, 3, "%02x", s[i]);
            strcat(result, "00");
            strcat(result, hex);
        } else { // 非 ASCII 字符
            char hex1[3] = {0};
            char hex2[3] = {0};
            snprintf(hex1, 3, "%02x", (s[i] & 0xF) << 4 | ((s[i + 1] >> 2) & 0xF));
            snprintf(hex2, 3, "%02x", (s[i + 1] & 0x3) << 6 | (s[i + 2] & 0x3F));
            strcat(result, hex1);
            strcat(result, hex2);
            i += 2;
        }
    }

    return result;
}

// 从字库文件获取字符对应的二进制编码字符串
// char* getPixBinStrFromString(XFont* xfont, const char* strUnicode) {
//     InitXFont(xfont, xfont->path);
//     char* ret = (char*)malloc(xfont->font_page + 1);
//     ret[0] = '\0';
//     if (xfont->file) {
//         uint8_t buf_seek_pixdata[xfont->font_page];
//         const char* chrAllUnicodes = xfont->strAllUnicodes;
//         for (int i = 0; i < strlen(strUnicode); i += 4) {
//             char _str[6];
//             sprintf(_str, "u%.4s", strUnicode + i);
//             char* chrFind = strstr(chrAllUnicodes, _str);
//             int p = chrFind - chrAllUnicodes;
//             int uIdx = p / 5;
//             int pixbeginidx = xfont->unicode_begin_idx + uIdx * xfont->font_page;
// 			fseek(xfont->file, pixbeginidx, SEEK_SET);
//             //xfont->file.seek(pixbeginidx);
// 			fread(buf_seek_pixdata, xfont->font_page, 1, xfont->file);
//             //xfont->file.read(buf_seek_pixdata, xfont->font_page);
//             char* su = getStringFromChars(buf_seek_pixdata, xfont->font_page);
//             strcat(ret, getPixDataFromHex(xfont,su));
//             free(su);
//         }
//     }
//     return ret;
// }


// // 从十六进制字符串获取像素数据
// char* getPixDataFromHex(const char* s) {
//     int l = strlen(s);
//     char* ret = (char*)malloc(l + 1);
//     ret[0] = '\0';
//     for (int i = 0; i < l; i++) {
//         int d = strchr(s64, s[i]) - s64;
//         for (int k = 3; k >= 0; k--) {
//             char ch = 48 + (int)bitRead(d, k);
//             strncat(ret, &ch, 1);
//         }
//     }
//     return ret;
// }

// 绘制单个字符
void DrawSingleStr(XFont* xfont, int x, int y, const char* strBinData, int fontColor, int backColor, bool ansiChar) {
    ESP_LOGE(TAG, "DrawSingleStr  strlen(strBinData) %d %s\n",strlen(strBinData),strBinData);
   for (int i = 0; i < strlen(strBinData); i++) {
        int pX1 = i % xfont->font_size;
        int pY1 = i / xfont->font_size;
        if(pX1 == 0)
        ESP_LOGE(TAG, "\n");

        if (ansiChar && (i % xfont->font_size > xfont->font_size / 2)) continue;

        if (strBinData[i] == '1') {
            if(xfont->tft){
                printf("*");
                lcdDrawPixel(xfont->tft,pX1 + x, pY1 + y, fontColor);
            }
        } else if (backColor != -1) {
            if(xfont->tft){
                printf( "-");
                lcdDrawPixel(xfont->tft,pX1 + x, pY1 + y, backColor);
            }
        }
    }
}

// // 绘制中文，参数为x坐标，y坐标，字符串，字体颜色
// void DrawChineseEx(XFont* xfont,int x, int y, const char*  str, int fontColor){
//     // 调用DrawChineseEx函数，参数为x坐标，y坐标，字符串，字体颜色，-1
//     DrawChineseEx(xfont,x,y,str,fontColor,-1);
// }
void DrawChineseEx(XFont* xfont,int x, int y, const char*  str, int fontColor,int backColor)
{

    DrawStrEx(xfont,x,y,str,fontColor,backColor);
    // Serial.printf("     屏幕显示所有汉字耗时:%.3f 秒.\r\n",time_spent/1000.0);
}


// 从字库文件获取字符对应的编码字符串
char*  getCodeDataFromFile(XFont* xfont,const char* strUnicode)
{

    if (!xfont->file) {
        ESP_LOGE(TAG, "Font file not opened");
        return NULL;
    }
    int f_cnt = strlen(strUnicode);
    char* result = (char*)heap_caps_malloc((xfont->font_page*(f_cnt/4)) + 1, MALLOC_CAP_SPIRAM);
    if (!result) {
        ESP_LOGE(TAG, "Failed to allocate memory for code data");
        return NULL;
    }
    memset(result, 0, xfont->font_page + 1);

    const char* chrAllUnicodes = xfont->strAllUnicodes;
    for (int i = 0; i < f_cnt; i += 4) { //每次读取一个Unicode字符的显示数据
        char _str[6] = "u";
        strncat(_str, strUnicode + i, 4);

        char* chrFind = strstr(chrAllUnicodes, _str);//在字库文件中查找字符对应的编码字符串
        if (!chrFind) {
            ESP_LOGE(TAG, "Unicode not found: %s", _str);
            free(result);
            return NULL;
        }

        int p = chrFind - chrAllUnicodes; //获取字符对应的编码字符串在字库文件中的偏移量
        int uIdx = p / 5; //获取字符对应的编码字符串在字库文件中的索引
        int pixbeginidx = xfont->unicode_begin_idx + uIdx * xfont->font_page; //获取字符对应的编码字符串在字库文件中的偏移量
        ESP_LOGE(TAG, "pixbeginidx : %d", pixbeginidx);
        fseek(xfont->file, pixbeginidx, SEEK_SET);
        fread(result+(xfont->font_page*i/4), 1, xfont->font_page, xfont->file);
    }

    return result;
}

char* getPixDataFromHex(XFont* xfont, const char* s ,char* out_result) {
    ESP_LOGE(TAG, "getPixDataFromHex  -- %d\n",strlen(s));
    int len = strlen(s);
    memset(out_result, 0, xfont->font_size * xfont->font_size + 1);
    // int cnt = 0;
    // for (int i = 0; i < len; i++) {
    //     int d = strtol((char[]){s[i], '\0'}, NULL, 16);
    //     for (int k = 3; k >= 0; k--) {
    //         result[cnt++] = '0' + (int)((d >> k) & 1);
    //     }
    // }
    int cnt=0;
    int cc = 3;
    if (xfont->bin_type == 64)
        cc = 5;//一位64进制数可以用5位二进制数表示
    for (int i = 0; i < len; i++)
    {
        int d=strchr( s64,s[i])-s64;//64进制字符串转10进制
        for (int k = cc; k >= 0&&cnt<(xfont->font_size * xfont->font_size); k--)
        {
            out_result[cnt]=48+(int)bitRead(d, k);//10进制转2进制
            cnt++;
        }
    }

    return 1;
}

// DrawStr2尝试处理半角英文问题，是对DrawStr的修正。
// 位置计算和字符显示分开
void DrawStrEx(XFont* xfont,int x, int y, const char*  str, int fontColor,int backColor)
{
    ESP_LOGE(TAG, "DrawStrEx  -- 1\n");
    InitXFont(xfont,xfont->path);
     if (!xfont->isInit) {
        ESP_LOGE(TAG, "Font not initialized");
        return;
    }

    char* strUnicode = getUnicodeFromUTF8(xfont, str);//将UTF-8字符串转换为Unicode字符串
    ESP_LOGE(TAG, "getUnicodeFromUTF8  -- %s\n",strUnicode);
    if (!strUnicode) {
        ESP_LOGE(TAG, "Failed to convert UTF-8 to Unicode");
        return;
    }

    char* codeData = getCodeDataFromFile(xfont, strUnicode);//获取Unicode字符串对应的编码数据
    ESP_LOGE(TAG, "getCodeDataFromFile  -- %s\n",codeData);
    if (!codeData) {
        ESP_LOGE(TAG, "Failed to get code data from file");
        free(strUnicode);
        return;
    }
    ESP_LOGE(TAG, "DrawStrEx  -- 2\n");
    int px = x;
    int py = y;
    int sep = 1; // 字间距

    for (int l = 0; l < strlen(strUnicode) / 4; l++) {
        char childUnicode[5] = {0};
        strncpy(childUnicode, strUnicode + 4 * l, 4);

        char childCodeData[xfont->font_page + 1];
        char childPixData[xfont->font_size * xfont->font_size + 1];
        strncpy(childCodeData, codeData + xfont->font_page * l, xfont->font_page);
        childCodeData[xfont->font_page] = '\0';
        ESP_LOGE(TAG, "DrawStrEx  -- 3\n");
        getPixDataFromHex(xfont, childCodeData,childPixData);
        // if (!childPixData) {
        //     ESP_LOGE(TAG, "Failed to get pixel data for Unicode: %s", childUnicode);
        //     continue;
        // }
        ESP_LOGE(TAG, "DrawStrEx  -- 4\n");
        int f = strtol(childUnicode, NULL, 16);

        if (f <= 127) { // ANSI 字符
            if (f == 13 || f == 10) { // 回车和换行
                px = 0;
                py += xfont->font_size + sep;
                continue;
            } else if (f == 9) { // Tab
                px += xfont->font_size + sep;
                continue;
            }

            if ((px + xfont->font_size / 2) > CONFIG_WIDTH) {
                px = 0;
                py += xfont->font_size + sep;
            }

            DrawSingleStr(xfont, px, py, childPixData, fontColor, backColor, true);
            px += xfont->font_size / 2 + sep;
        } else { // 非 ANSI 字符
            if ((px + xfont->font_size) > CONFIG_WIDTH) {
                px = 0;
                py += xfont->font_size + sep;
            }

            DrawSingleStr(xfont, px, py, childPixData, fontColor, backColor, false);
            px += xfont->font_size + sep;
        }

    }

    free(strUnicode);
    free(codeData);
}
